namespace RBAC.Read.Api.Application.Handler
{
    using System;
    using System.Linq;
    using System.Collections.Generic;
    using Microsoft.EntityFrameworkCore;
    using RBAC.Domain.HXJX;
    using RBAC.ErrorCode;
    using RBAC.Interstructrue;
    using RBAC.Read.Api.Application.Dto;
    using RBAC.Read.Api.Application.Interfaces;
    using System.IO;
    using NPOI.SS.UserModel;
    using NPOI.XSSF.UserModel;

    /// <summary>
    /// 生产工单（读侧）服务实现。
    /// </summary>
    public class ProductionWorkOrderReadService : IProductionWorkOrderReadService
    {
        private readonly RBACDbContext _db;
        public ProductionWorkOrderReadService(RBACDbContext db)
        {
            _db = db;
        }

        /// <summary>
        /// 生产工单列表查询（简化分页实现）
        /// </summary>
        public APIPaging<WorkOrderListItemDto> GetProductionWorkOrderList(WorkOrderListFilterDto filter)
        {
            var query = _db.ProductionWorkOrder.AsNoTracking().AsQueryable();

            if (!string.IsNullOrWhiteSpace(filter.OrderCode))
                query = query.Where(x => x.OrderCode!.Contains(filter.OrderCode));
            if (!string.IsNullOrWhiteSpace(filter.OrderType))
                query = query.Where(x => x.OrderType == filter.OrderType);
            if (!string.IsNullOrWhiteSpace(filter.OrderStatus))
                query = query.Where(x => x.OrderStatus == filter.OrderStatus);
            if (filter.OrderDateStart.HasValue)
                query = query.Where(x => x.OrderDate >= filter.OrderDateStart);
            if (filter.OrderDateEnd.HasValue)
                query = query.Where(x => x.OrderDate <= filter.OrderDateEnd);
            if (!string.IsNullOrWhiteSpace(filter.ProductName))
                query = query.Where(x => x.ProductName!.Contains(filter.ProductName));

            var total = query.Count();
            var pageSize = filter.PageSize > 0 ? filter.PageSize : 10;
            var pageIndex = filter.PageIndex > 0 ? filter.PageIndex : 1;

            var rows = query
                .OrderByDescending(x => x.CreateTime)
                .Skip((pageIndex - 1) * pageSize)
                .Take(pageSize)
                .Select(x => new WorkOrderListItemDto
                {
                    OrderCode = x.OrderCode!,
                    OrderType = x.OrderType,
                    OrderDate = x.OrderDate ?? DateTime.MinValue,
                    OrderStatus = x.OrderStatus,
                    CustomerName = x.CustomerName,
                    ProductName = x.ProductName ?? string.Empty,
                    Spec = x.Spec,
                    Unit = x.Unit,
                    Quantity = x.Quantity ?? 0,
                    DeliveryDate = x.DeliveryDate,
                    Priority = x.Priority,
                    SalesPerson = x.SalesPerson,
                    BusinessType = x.BusinessType,
                    Remark = x.Remark,
                    Auditor = x.Auditor,
                    AuditDate = x.AuditDate
                })
                .ToList();

            return new APIPaging<WorkOrderListItemDto>
            {
                Code = APIEnums.Success,
                Msg = string.Empty,
                TotalCount = total,
                PageDatas = rows
            };
        }

        /// <summary>
        /// 生产工单详情查询
        /// </summary>
        public APIResult<WorkOrderDetailDto> GetProductionWorkOrderDetail(string orderCode)
        {
            var result = new APIResult<WorkOrderDetailDto>();
            if (string.IsNullOrWhiteSpace(orderCode))
            {
                result.Code = APIEnums.Error;
                result.Msg = "orderCode 不能为空";
                return result;
            }

            var order = _db.ProductionWorkOrder.AsNoTracking()
                .FirstOrDefault(x => x.OrderCode == orderCode);

            if (order == null)
            {
                result.Code = APIEnums.Success;
                result.Msg = string.Empty;
                result.Data = new WorkOrderDetailDto
                {
                    BaseInfo = new WorkOrderBaseInfoDto { OrderCode = orderCode }
                };
                return result;
            }

            var woId = order.Id;

            var bom = _db.ProductionWorkOrderBomItem.AsNoTracking()
                .Where(x => x.WorkOrderId == woId)
                .OrderBy(x => x.LineNo)
                .Select(x => new WorkOrderBomItemDto
                {
                    WorkOrderId = x.WorkOrderId,
                    LineNo = x.LineNo,
                    MaterialId = x.MaterialId ?? 0,
                    MaterialCode = x.MaterialCode,
                    MaterialName = x.MaterialName,
                    Spec = x.Spec,
                    Unit = x.Unit,
                    Qty = x.Qty ?? 0,
                    LossRate = x.LossRate ?? 0,
                    WarehouseId = x.WarehouseId,
                    WarehouseName = x.WarehouseName,
                    Remark = x.Remark
                })
                .ToList();

            var processes = _db.ProductionWorkOrderProcess.AsNoTracking()
                .Where(x => x.WorkOrderId == woId)
                .OrderBy(x => x.SeqNo)
                .Select(x => new WorkOrderProcessDto
                {
                    WorkOrderId = x.WorkOrderId,
                    SeqNo = x.SeqNo,
                    ProcessCode = x.ProcessCode ?? string.Empty,
                    ProcessName = x.ProcessName ?? string.Empty,
                    WorkCenterId = x.WorkCenterId,
                    WorkCenterName = x.WorkCenterName,
                    StdHours = x.StdHours,
                    Uom = x.Uom,
                    PlanStartTime = x.PlanStartTime,
                    PlanEndTime = x.PlanEndTime,
                    TransferQty = x.TransferQty,
                    GoodQty = x.GoodQty,
                    ScrapQty = x.ScrapQty,
                    WipQty = x.WipQty,
                    Remark = x.Remark
                })
                .ToList();

            var atts = _db.ProductionWorkOrderAttachment.AsNoTracking()
                .Where(x => x.WorkOrderId == woId)
                .OrderByDescending(x => x.UploadTime)
                .Select(x => new WorkOrderAttachmentDto
                {
                    FileName = x.FileName ?? string.Empty,
                    FileType = x.FileType,
                    FileUrl = x.FileUrl,
                    Uploader = x.Uploader,
                    UploadTime = x.UploadTime,
                    Remark = x.Remark
                })
                .ToList();

            var baseInfo = new WorkOrderBaseInfoDto
            {
                OrderCode = order.OrderCode ?? string.Empty,
                OrderType = order.OrderType,
                OrderDate = order.OrderDate ?? DateTime.MinValue,
                OrderStatus = order.OrderStatus,
                CustomerName = order.CustomerName,
                ProductName = order.ProductName ?? string.Empty,
                Spec = order.Spec,
                Unit = order.Unit,
                Quantity = order.Quantity ?? 0,
                DeliveryDate = order.DeliveryDate,
                Priority = order.Priority,
                SalesPerson = order.SalesPerson,
                BusinessType = order.BusinessType,
                Remark = order.Remark,
                Auditor = order.Auditor,
                AuditDate = order.AuditDate
            };

            result.Code = APIEnums.Success;
            result.Msg = string.Empty;
            result.Data = new WorkOrderDetailDto
            {
                BaseInfo = baseInfo,
                BomItems = bom,
                Processes = processes,
                Attachments = atts
            };
            return result;
        }

        /// <summary>
        /// 导出生产工单列表为 Excel（xlsx）。
        /// </summary>
        /// <param name="filter">筛选条件（忽略分页参数）。</param>
        /// <returns>APIResult<byte[]>: 文件二进制。</returns>
        public APIResult<byte[]> ExportProductionWorkOrders(WorkOrderListFilterDto filter)
        {
            try
            {
                var query = _db.ProductionWorkOrder.AsNoTracking().AsQueryable();

                if (!string.IsNullOrWhiteSpace(filter.OrderCode))
                    query = query.Where(x => x.OrderCode!.Contains(filter.OrderCode));
                if (!string.IsNullOrWhiteSpace(filter.OrderType))
                    query = query.Where(x => x.OrderType == filter.OrderType);
                if (!string.IsNullOrWhiteSpace(filter.OrderStatus))
                    query = query.Where(x => x.OrderStatus == filter.OrderStatus);
                if (filter.OrderDateStart.HasValue)
                    query = query.Where(x => x.OrderDate >= filter.OrderDateStart);
                if (filter.OrderDateEnd.HasValue)
                    query = query.Where(x => x.OrderDate <= filter.OrderDateEnd);
                if (!string.IsNullOrWhiteSpace(filter.ProductName))
                    query = query.Where(x => x.ProductName!.Contains(filter.ProductName));

                var rows = query
                    .OrderByDescending(x => x.CreateTime)
                    .Select(x => new WorkOrderListItemDto
                    {
                        OrderCode = x.OrderCode!,
                        OrderType = x.OrderType,
                        OrderDate = x.OrderDate ?? DateTime.MinValue,
                        OrderStatus = x.OrderStatus,
                        CustomerName = x.CustomerName,
                        ProductName = x.ProductName ?? string.Empty,
                        Spec = x.Spec,
                        Unit = x.Unit,
                        Quantity = x.Quantity ?? 0,
                        DeliveryDate = x.DeliveryDate,
                        Priority = x.Priority,
                        SalesPerson = x.SalesPerson,
                        BusinessType = x.BusinessType,
                        Remark = x.Remark,
                        Auditor = x.Auditor,
                        AuditDate = x.AuditDate
                    })
                    .ToList();

                if (rows.Count == 0)
                {
                    return new APIResult<byte[]>
                    {
                        Code = APIEnums.Fail,
                        Msg = "没有可导出的生产工单数据",
                        Data = Array.Empty<byte>()
                    };
                }

                var headers = new[]
                {
                    "工单号","工单类型","工单日期","工单状态","客户名称","产品名称","规格","单位","数量",
                    "交期","优先级","业务员","业务类型","备注","审核人","审核日期"
                };

                var wb = new XSSFWorkbook();
                var sheet = wb.CreateSheet("生产工单");

                // header
                var headerRow = sheet.CreateRow(0);
                for (int i = 0; i < headers.Length; i++) headerRow.CreateCell(i).SetCellValue(headers[i]);

                // body
                for (int r = 0; r < rows.Count; r++)
                {
                    var m = rows[r];
                    var row = sheet.CreateRow(r + 1);
                    row.CreateCell(0).SetCellValue(m.OrderCode);
                    row.CreateCell(1).SetCellValue(m.OrderType ?? string.Empty);
                    row.CreateCell(2).SetCellValue(m.OrderDate == DateTime.MinValue ? string.Empty : m.OrderDate.ToString("yyyy-MM-dd"));
                    row.CreateCell(3).SetCellValue(m.OrderStatus ?? string.Empty);
                    row.CreateCell(4).SetCellValue(m.CustomerName ?? string.Empty);
                    row.CreateCell(5).SetCellValue(m.ProductName);
                    row.CreateCell(6).SetCellValue(m.Spec ?? string.Empty);
                    row.CreateCell(7).SetCellValue(m.Unit ?? string.Empty);
                    row.CreateCell(8).SetCellValue(Convert.ToDouble(m.Quantity));
                    row.CreateCell(9).SetCellValue(m.DeliveryDate.HasValue ? m.DeliveryDate.Value.ToString("yyyy-MM-dd") : string.Empty);
                    row.CreateCell(10).SetCellValue(m.Priority ?? string.Empty);
                    row.CreateCell(11).SetCellValue(m.SalesPerson ?? string.Empty);
                    row.CreateCell(12).SetCellValue(m.BusinessType ?? string.Empty);
                    row.CreateCell(13).SetCellValue(m.Remark ?? string.Empty);
                    row.CreateCell(14).SetCellValue(m.Auditor ?? string.Empty);
                    row.CreateCell(15).SetCellValue(m.AuditDate.HasValue ? m.AuditDate.Value.ToString("yyyy-MM-dd") : string.Empty);
                }

                for (int c = 0; c < headers.Length; c++) sheet.AutoSizeColumn(c);

                using var ms = new MemoryStream();
                wb.Write(ms);
                ms.Flush();
                var bytes = ms.ToArray();

                return new APIResult<byte[]>
                {
                    Code = APIEnums.Success,
                    Msg = $"成功导出{rows.Count}条数据",
                    Data = bytes
                };
            }
            catch (Exception ex)
            {
                return new APIResult<byte[]>
                {
                    Code = APIEnums.Fail,
                    Msg = "导出失败：" + ex.Message,
                    Data = Array.Empty<byte>()
                };
            }
        }
    }
}
